Technotes
Driver Loader Library Call GetDriverInformation: A Bug & Workaround
This Technote describes a workaround to a bug in the first version of the Driver Loader Library in System 7.5.2 and System Update 7.5.3. (The bug should be fixed in later versions of the Mac OS.) As of this writing, the Driver Loader Library is only available on Power Macintoshes that support PCI cards (for example:Power Mac 7200, 7500, 8500 and 9500). There is a bug in the routine GetDriverInformation that can possibly cause an overwriting past the end of the name string that is passed in.
This Technote is directed primarily at writers or family experts and especially
applications that get information about drivers.
Defining the ProblemIn the Driver Loader Library, there is a bug in the routine GetDriverInformation that can possibly cause an overwriting past the end of the name string that is passed in.This bug surfaces only when calling GetDriverInformation() for a driver that has had its Device Control Entry fields zeroed when it was closed (the Chooser driver has been observed to exhibit this behavior). The bug occurs because GetDriverInformation() does not check for zeroed fields before using the dCtlDriver field to reference the driver's name; instead, it copies a garbage string from low memory into the name string passed as a parameter to GetDriverInformation(). If the first byte of this garbage string is larger than the number bytes of storage allocated by the caller for the name string, then the caller's data located just past the end of name's storage will be overwritten with garbage. You can see the zeroing out of fields for the Chooser's driver by following these steps using any version of MacsBug: 1. Open the Chooser. 2. Drop into MacsBug and type:
drvr <return>3. Look down the list of drivers in the Driver column of the drvr display and see the Chooser (on my machine it's at dNum 0xF). To see what the Chooser's DCE fields look like before the zeroing type:
dm xxxxx dctlentry <return>(where xxxxx is the hexidecimal number in the Chooser's row in the "DCE at"column in the drvr display) 4. Exit Macsbug by hitting Command-g. 5. Close the Chooser window. 6. Drop into MacsBug and type:
drvr <return>You'll see that name Chooser is replace by blanks in the row that it was in. 7. To see the zeroing of DCE fields type:
dm xxxxx dctlentry <return>(again, where xxxxx is the hexidecimal number in the Chooser's row in the "DCE at" column in the drvr display). You'll see that all fields except the RefNum field have been zeroed. It's doubtful that any expert code will encounter this problem if the expert code executes pre-Finder; applications that execute after the Finder boots are the most likely victims. If your code calls GetDriverInformation() after a user has a chance to close one of these "zeroed-out" drivers (and the DCE fields are thus zeroed), then you will need this workaround. If you call GetDriverInformation only for a driver that you know doesn't have its Device Control Entry fields zeroed upon closing, then you don't need this workaround because the bug will not appear. It is only when you traverse the unit table, calling GetDriverInformation for unknown drivers, that you need to be aware of the workaround.
GetDriverInformationHere is the declaration for GetDriverInformation as gleaned from the universal headers file, Devices.h:
extern OSErr GetDriverInformation (DriverRefNum refNum, UnitNumber *unitNum, DriverFlags *flags, DriverOpenCount *count, StringPtr name, // ** this is the field we are concerned with// RegEntryID *device, CFragHFSLocator *driverLoadLocation, CFragConnectionID *fragmentConnID, DriverEntryPointPtr *fragmentMain, DriverDescription *driverDesc);It is the StringPtr name parameter that we are concerned with. If you allocate, for example, a Str31 to use to pass in as the StringPtr, then (if the erroneous byte GetDriverInformation thinks is the length byte of the garbage string is greater than 0x1f, or 31 decimal) GetDriverInformation will unwittingly copy all the garbage bytes to your code without regard to the actual location of the end of the name string. Solving the ProblemThe workaround is simple:allocate a String255 for the name parameter passed into GetDriverInformation() rather than some shorter-length string. This means any garbage copied to the string will be contained in that string rather than any other data. If you're familiar with GetDriverInformation, that's all you need to know:use a Str255 for the name parameter rather than a shorter string and you're protected. If you're not familiar with GetDriverInformation and would like to see some code to traverse the unit table, sample code is provided here for your information. You also have to take precautions about using the garbage string data as well (if you were going to display the driver name in an application, you would probably want to check for non-printing characters if displaying them would cause problems in your code. You might want to make sure the garbage length of the name string isn't too long for your code to handle).Sample Code Using GetDriverInformation To Iterate Over the Driver Unit TableTo drive the point home about using a Str255, and also to alert you to another mandatory initializing of the FSSpec field of the driverLoadLocation struct, (another input of GetDriverInformation), here is some barebones sample code. Note that traversing the unit table using GetDriverInformation() is not the most efficient way to discover which units are empty and which are full. Use the Driver Loader Library routine, LookupDrivers() for that.
void TraverseDrivers() { OSErr err = noErr; DriverRefNum refNum; UnitNumber unitNum; DriverFlags flags; DriverOpenCount count; RegEntryID device; CFragHFSLocator driverLoadLocation; DriverDescription driverDesc; // Str63 theName; // BAD, not long enough Str255 theName; // GOOD:THIS IS THE WORKAROUND! FSSpec loadLocSpec; short i; // this is another caveat about using GetDriverInformation(); you must // initialize the FSSpec ptr field of the driverLoadLocation struct to // point to an allocated FSSpec because GetDriverInformation assumes you // have. This is done is the next line below. driverLoadLocation.u.onDisk.fileSpec = &loadLocSpec; for( i = 0; i <= HighestUnitNumber(); ++i ){ refNum = ~i; // convert the unit number to a driver refNum. err = GetDriverInformation( refNum, &unitNum, &flags, &count, theName, &device, &driverLoadLocation, &fragmentConnID, &fragmentMain, &driverDesc); if( err != noErr ){ // there's a driver for this refNum // Do whatever it was you wanted to do with the information // BEWARE: If the driver is a non-native driver, that is a // 68k driver of pre-PCI-supporting Macintosh, the device, // driverLoadLocation, fragmentConnID, fragmentMain, and // driverDesc inputs above will be set to nil after the call // because these fields don't apply to 68k drivers. } } // for } // end TraverseDrivers() Reference for GetDriverInformationGetDriverInformationGetDriverInformation returns a number of pieces of information about an installed driver.
OSErr GetDriverInformation (DriverRefNum refNum, UnitNumber *unitNum, DriverFlags *flags, DriverOpenCount *count, StringPtr name, RegEntryID *device, CFragHFSLocator *driverLoadLocation, CFragConnectionID *fragmentConnID, DriverEntryPointPtr *fragmentMain, DriverDescription *driverDesc); refNum refNum of driver to examine unit resulting unit number flags resulting DCE flag bits count number of times driver has been opened name resulting driver name device resulting Name Registry device specification driverLocation resulting CFM fragment locator (from which the driver was loaded) fragmentConnID resulting CFM connection ID fragmentMain resulting pointer to DoDriverIO driverDesc resulting pointer to DriverDescription
noErr 0 No error badUnitErr -21 Bad unit number unitEmptyErr -22 Empty unit number SummaryTo protect yourself against having GetDriverInformation copy garbage into the passed StringPtr name parameter when a driver has its Device Control Entry (DCE) fields zeroed upon closing (the Chooser, for example), allocate a large enough string (for example, String255) for the name parameter. This will assure that any garbage copied to the string will be contained in that string.See Designing PCI Cards and Drivers for Power Macintosh Computers for further documentation on GetDriverInformation or any other Driver Loader Library calls. Technotes Previous Technote | Contents | Next Technote |